﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Microsoft.WindowsMobile.Samples.Location;
using Interfaces;

namespace GPS
{
    public class GPS : IGPSOriginator
    {
        ctlMain mainInterface = new ctlMain();

        public System.Windows.Forms.UserControl MainInterface
        {
            get { return mainInterface; }
        }

        public string Name
        {
            get { return "GPS"; }
        }

        CustomControls.AlphaImage IModule.IconEnabled
        {
            get { return CustomControls.AlphaImage.CreateFromResource("GPS.Resources.status-gps-active.png"); }
        }

        CustomControls.AlphaImage IModule.IconDisabled
        {
            get { return CustomControls.AlphaImage.CreateFromResource("GPS.Resources.status-gps-inactive.png"); }
        }

        public bool Sleep()
        {
            throw new NotImplementedException();
        }

        public bool Wake()
        {
            throw new NotImplementedException();
        }

        private Gps _gps = new Gps();
        private GpsPosition _currentPosition = null;
        private GpsDeviceState device =null;
        private IPositionHandler host;
        private bool DataValid = false;
        private System.Windows.Forms.Timer DataRequestTimer = new System.Windows.Forms.Timer();
        private System.Windows.Forms.Timer DataValidTimer = new System.Windows.Forms.Timer();
        private System.Windows.Forms.Timer GPSTimer = new System.Windows.Forms.Timer();
        private System.Windows.Forms.Timer OnOffTimer = new System.Windows.Forms.Timer();
        private double mindist = 0;
        public int Rate
        {
            get
            {
                return GPSTimer.Interval;
            }
            set
            {
                GPSTimer.Interval = value;
            }
        }
        public int DataRequestInterval
        {
            get
            {
                return DataRequestTimer.Interval;
            }
            set
            {
                DataRequestTimer.Interval = value;
            }
        }
        public int DataValidInterval
        {
            get
            {
                return DataValidTimer.Interval;
            }
            set
            {
                DataValidTimer.Interval = value;
            }
        }


        public double MinDistance //ezzel lehet beállítani mi legyen az a távolség (méterben) ami alatt ne legyen newsignalevent
        {
            get 
            {
                return mindist;
            }
            set
            {
                if(value>0)
                mindist = value;
            }
        }
         public GPS()
        {
            
            
            DataRequestInterval = 20000;
            DataRequestTimer.Tick += new EventHandler(DataRequestTimer_Tick);
            DataValidInterval = 20000;
            DataValidTimer.Tick += new EventHandler(DataValidTimer_Tick);
            OnOffTimer.Tick += new EventHandler(OnOffTimer_Tick);
            GPSTimer.Tick += new EventHandler(GPSTimer_Tick);
            GPSTimer.Interval = 1000;
        }

        
       
        ~GPS()
        {
            SetRadioOff();
        }

        public GPSData CurrentLocation
        {
            get
            {
                if (_currentPosition != null)
                {
                    try // Ideiglenesen hozzáadtam ezt, mert állandóan kifagyott miatta a progi...
                    {
                        return new GPSData() { Latitude = _currentPosition.Latitude, Longitude = _currentPosition.Longitude, Time = _currentPosition.Time };
                    }
                    catch (Exception)
                    {
                       // host.WriteDebugLog(e.Message);
                        return GPSData.Empty;
                    }
                }
                else
                {
                    return GPSData.Empty;
                }
            }
        }

        void OnOffTimer_Tick(object sender, EventArgs e)
        {
            OnOffTimer.Enabled = false;
            if (GPSTimer.Enabled)
                SetRadioOff();
            else
                SetRadioOn();
        }
        void DataRequestTimer_Tick(object sender, EventArgs e)
        {
            DataRequestTimer.Enabled = false;
            OnRequestedDataAvailable(new PositionEventArgs());
            //RequestedDataAvailable(this, EventArgs.Empty, null);

        }
        void DataValidTimer_Tick(object sender, EventArgs e)//ha ez beüt, akkor ezalatt az idő alatt nem jött új adat és így a bent lévő adat már nem érvényes
        {
            DataValidTimer.Enabled = false;

            UpdateDataValid(DataValidTimer.Enabled);

        }

        void GPSTimer_Tick(object sender, EventArgs e)
        {
            GPSData oldpos = new GPSData();
            oldpos = CurrentLocation;
            _currentPosition = _gps.GetPosition();
            List<IPositionData> pos = new List<IPositionData>();
            pos.Add(CurrentLocation);
            if (mindist > 0)
            {
                if (CalculateDistance(CurrentLocation, oldpos) >= MinDistance)
                {
                    OnNewSignal(new PositionEventArgs(pos, PositionEventArgs.Operation.New));
                }
            }
            else
            {
                OnNewSignal(new PositionEventArgs(pos, PositionEventArgs.Operation.New));
            }

            if (DataRequestTimer.Enabled)//ha kértek adatot akkor visszaküldjuk a frissen beérkező adatot
            {
                DataRequestTimer.Enabled = false;
                
                OnRequestedDataAvailable(new PositionEventArgs(pos, PositionEventArgs.Operation.OnDemand));


            }
            //DataValidTimer = new System.Windows.Forms.Timer();
            if (DataValidTimer.Enabled)                 //ez azért kell, mert a timer úgy indul újra  0tól ha előtte le volt tiltva és Az Enabledet True-ra állítjuk
                DataValidTimer.Enabled = false;
            DataValidTimer.Enabled = true;
            UpdateDataValid(DataValidTimer.Enabled);//Az adat érvényességét állítjuk be
        }

        double CalculateDistance(GPSData Pos1, GPSData Pos2)//két gpsData közötti távolság méterben
        {
            double R_2 = 12742.0;                   // Two times the Earth maen radius (6371 meters)
            double dlon, dlat, a;
            double Deg2Rad = 0.017453292519943;     // Pi / 180 deg

            dlon = (Pos2.Longitude - Pos1.Longitude) * Deg2Rad; // difference in longitude 
            dlat = (Pos2.Latitude - Pos1.Latitude) * Deg2Rad; // difference in latitude 

            a = Math.Pow(Math.Sin(dlat / 2.0), 2.0) + (Math.Cos(Pos1.Latitude * Deg2Rad) * Math.Cos(Pos2.Latitude * Deg2Rad) * Math.Pow(Math.Sin(dlon / 2.0), 2.0));

            return 1000*R_2 * Math.Asin(Math.Min(1.0, Math.Sqrt(a)));   // Final distance is in km. 
        }
      //  private void _gps_LocationChanged(object sender, Microsoft.WindowsMobile.Samples.Location.LocationChangedEventArgs args)
        //{
        //    _currentPosition = args.Position;
        //   // _currentPosition.
        //    if (DataRequestTimer.Enabled)//ha kértek adatot akkor visszaküldjuk a frissen beérkező adatot
        //    {
        //        DataRequestTimer.Enabled = false;
        //        IPositionData[] pos = new IPositionData[1];
        //        pos[0] = CurrentLocation;
        //        OnRequestedDataAvailable(new PositionEventArgs(pos));
                

        //    }
        //    //DataValidTimer = new System.Windows.Forms.Timer();
        //    if (DataValidTimer.Enabled)                 //ez azért kell, mert a timer úgy indul újra  0tól ha előtte le volt tiltva és Az Enabledet True-ra állítjuk
        //        DataValidTimer.Enabled = false;
        //    DataValidTimer.Enabled = true;
        //    UpdateDataValid(DataValidTimer.Enabled);//Az adat érvényességét állítjuk be



        //}

        /// <summary>
        /// Jelenleg időfüggés alapján érvényes az adat, de később bővíthető ebben a függvényben
        /// </summary>
        /// <param name="valid"></param>
        private void UpdateDataValid(bool valid)
        {
            DataValid = valid;
        }

        #region IPositionOriginator Members

        public bool GetRadioStatus()
        {
            device =_gps.GetDeviceState();

            if (device.DeviceState == GpsServiceState.On)
                return true;
            else return false;

        }

        public int SetRadioOn()
        {
            try
            {
                if (!_gps.Opened)
                {
                    _gps.Open();

                }
               // _gps.LocationChanged += new Microsoft.WindowsMobile.Samples.Location.LocationChangedEventHandler(_gps_LocationChanged);
                GPSTimer.Enabled = true;
                _currentPosition = _gps.GetPosition();
                OnRadioSwitchedOn(EventArgs.Empty);
                
            }
            catch
            {
                return 1;
            }
            return 0;
        }

        public int SetRadioOff()
        {
            try
            {
                if (_gps.Opened)
                {
                    _gps.Close();
                }
               // _gps.LocationChanged -= new Microsoft.WindowsMobile.Samples.Location.LocationChangedEventHandler(_gps_LocationChanged);
                GPSTimer.Enabled = false;
                OnRadioSwitchedOff(EventArgs.Empty);
                
            }
            catch
            {
                return 1;
            }
            return 0;
        }

        public int SetRadioOn(int interval)
        {
            try
            {
                if (OnOffTimer.Enabled)
                    OnOffTimer.Enabled = false;
                OnOffTimer.Interval = interval * 1000;
                if (!GPSTimer.Enabled)
                    SetRadioOn();
                OnOffTimer.Enabled = true;
            }

            catch
            {
                return 1;
            }
            return 0;

        }
        public int SetRadioOff(int interval)
        {
            try
            {
                if (OnOffTimer.Enabled)
                    OnOffTimer.Enabled = false;
                OnOffTimer.Interval = interval * 1000;
                if (GPSTimer.Enabled)
                    SetRadioOff();
                OnOffTimer.Enabled = true;
            }

            catch
            {
                return 1;
            }
            return 0;
        }

        public int DataRequest()
        {

            try
            {
                if (DataValid)//Ha érvényes az adat akkor egyből küldjük
                {
                    List<IPositionData> position = new List<IPositionData>();
                    position.Add(CurrentLocation);
                   OnRequestedDataAvailable(new PositionEventArgs(position, PositionEventArgs.Operation.OnDemand));
                   // RequestedDataAvailable(this, EventArgs.Empty, pos);
                }
                else//ha nem akkor indul a timer, ha beüt akkor null-t küldünk vissza
                {
                   // DataRequestTimer = new System.Windows.Forms.Timer();
                    if (DataRequestTimer.Enabled) //ez azért kell, mert a timer úgy indul újra  0tól ha előtte le volt tiltva és Az Enabledet True-ra állítjuk
                        DataRequestTimer.Enabled = false;
                    DataRequestTimer.Enabled = true;
                    
                    
                }
                return 0;
            }
            catch (Exception)
            {

                return 1;
            }
            
        }

       

        public new PositionOriginator GetType() //TODO: Rename this method so it doesn't hide Object.GetType
        {
            return PositionOriginator.Gps;
        }



public IPositionHandler Host
{
	  get 
	{ 
		return host;
	}
	  set 
	{
        host = value;
	}
}




public void Initialize()
{
    Console.WriteLine("GPS module initialized.");
}



// ezeket technikai okokból kellett a gps-nél is implementálni (amikor a modulok betöltődnek, akkor csak az IPositionOriginator interfészt implementálják
// viszont az eseményeket ennek ellenére be kell kötni)
// GPS esetén is hasonló viselkedést várunk, mint a Proximity jellegű originatoroknál, de természetesen az így nyert
// adatok másképp lesznek kezelve (ezzel neked nem kell törődnöd)
        public event NewSignalEventHandler NewSignalEvent;
        public event BestSignalEventHandler BestSignalEvent;



        public void OnNewSignal(PositionEventArgs e)
        {
            if(NewSignalEvent != null)
            NewSignalEvent(this, e);
        }

        public void OnBestSignal(PositionEventArgs e)
        {
            throw new NotImplementedException();
        }

        

       


        public void OnRadioSwitchedOff(EventArgs e)
        {
            if(RadioSwitchedOffEvent != null)
            RadioSwitchedOffEvent(this, e);
        }

        public void OnRadioSwitchedOn(EventArgs e)
        {
            if (RadioSwitchedOnEvent != null)
            RadioSwitchedOnEvent(this, e);
        }

        public void OnRequestedDataAvailable(PositionEventArgs e)
        {

           
            if (RequestedDataAvailable != null)
                RequestedDataAvailable(this,e);
        }

        public event RequestedDataAvailableHandler RequestedDataAvailable;

        public event RadioSwitchedOffEventHandler RadioSwitchedOffEvent;

        public event RadioSwitchedOnEventHandler RadioSwitchedOnEvent;

        #endregion

        #region IGPSOriginator Members

        public GPSData GetData()
        {
            return CurrentLocation;
        }

        #endregion


        #region IDisposable Members

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
